package com.fy.service.server.channel;
import com.fy.service.server.config.NettyConfig;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class SocketServerHelper {
    static final Logger logger = LoggerFactory.getLogger(SocketServerHelper.class);
    public static EventLoopGroup bossGroup;
    private static int WORKER_GROUP_SIZE = Runtime.getRuntime().availableProcessors() * 2;
    private static EventLoopGroup workerGroup;
    private static Class<? extends ServerChannel> channelClass;

    @Autowired
    private NettyConfig nettyConfig;

    @Autowired
    private SocketChannelInitializer socketChannelInitializer;

    @Autowired
    private WebsocketChannelInitializer websocketChannelInitializer;

    private ServerBootstrap socketErverBootstrap = null;

    private ServerBootstrap WebsocketErverBootstrap = null;

    //服务停止方法
    public static void shutdown() {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }

    //基础网络协议配置
    private ServerBootstrap baseConfig() {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.SO_REUSEADDR, true)
                .childOption(ChannelOption.ALLOCATOR, new PooledByteBufAllocator(false))
                .childOption(ChannelOption.SO_RCVBUF, 1048576)
                .childOption(ChannelOption.SO_SNDBUF, 1048576);

        bossGroup = new NioEventLoopGroup(1);
        workerGroup = new NioEventLoopGroup(WORKER_GROUP_SIZE);
        channelClass = NioServerSocketChannel.class;
        logger.info("workerGroup size:" + WORKER_GROUP_SIZE);
        logger.info("preparing to start spider server...");
        serverBootstrap.group(bossGroup, workerGroup);
        serverBootstrap.channel(channelClass);
        //证书配置
/*        KeyManagerFactory keyManagerFactory = null;
        KeyStore keyStore = KeyStore.getInstance("JKS");
        String classPath = System.getProperty("user.dir")+"/";
        keyStore.load(new FileInputStream(classPath + nettyConfig.getPath()),nettyConfig.getKey().toCharArray());
        keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
        keyManagerFactory.init(keyStore,nettyConfig.getKey().toCharArray());
        List<String> ciphers = new ArrayList<String>();
        ciphers.add("ECDHE-RSA-AES128-SHA");
        ciphers.add("ECDHE-RSA-AES256-SHA");
        ciphers.add("AES128-SHA");
        ciphers.add("AES256-SHA");
        ciphers.add("DES-CBC3-SHA");
        SslContext sslContext = SslContextBuilder.forServer(keyManagerFactory)
        		.sslProvider(SslProvider.OPENSSL).ciphers(ciphers)
        		.build();
        sslChannelInitializer.setContext(sslContext);*/
        return serverBootstrap;

    }


    //tcp 服务启动方法
    public void startSocketServer() throws Exception {
        socketErverBootstrap = this.baseConfig();
        socketErverBootstrap.childHandler(socketChannelInitializer);
        socketErverBootstrap.bind(nettyConfig.getPort()).addListeners(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture f) throws Exception {
                if (f.isSuccess()) {
                    logger.info("Started Tcp Server: " + nettyConfig.getPort());
                } else {
                    logger.info("Started Tcp Server Failed: " + nettyConfig.getPort());
                    f.channel().eventLoop().schedule(() -> doBind(socketErverBootstrap, nettyConfig.getPort()), 1, TimeUnit.SECONDS);
                }
            }
        }).sync();
        logger.info("socket server start sucess, listening on port " + nettyConfig.getPort() + ".");
    }

    //webservice 服务启动方法
    public void startWebsocketServer() throws Exception {
        WebsocketErverBootstrap = this.baseConfig();
        WebsocketErverBootstrap.childHandler(websocketChannelInitializer);
        WebsocketErverBootstrap.bind(nettyConfig.getWebport()).addListeners(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture f) throws Exception {
                if (f.isSuccess()) {
                    logger.info("Started webservice Server: " + nettyConfig.getWebport());
                } else {
                    logger.info("Started webservice Server Failed: " + nettyConfig.getWebport());
                    f.channel().eventLoop().schedule(() -> doBind(WebsocketErverBootstrap, nettyConfig.getWebport()), 1, TimeUnit.SECONDS);
                }
            }
        }).sync();
        logger.info("websocket server start sucess, listening on port " + nettyConfig.getWebport() + ".");
    }


    //端口绑定
    protected void doBind(ServerBootstrap serverBootstrap, Integer port) {
        serverBootstrap.bind(port).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture f) throws Exception {
                if (f.isSuccess()) {
                    logger.info("Started Tcp Server: " + port);
                } else {
                    logger.info("Started Tcp Server Failed: " + nettyConfig.getPort());
                }
            }
        });
    }


}